//! Database entities for introspection
//! 
//! This module contains SeaORM entities that map to information_schema tables
//! for database introspection purposes.

use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

/// Entity for information_schema.tables
pub mod tables {
    use super::*;
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "tables", schema_name = "information_schema")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_name: String,
        pub table_type: Option<String>,
        pub engine: Option<String>,
        pub version: Option<i64>,
        pub row_format: Option<String>,
        pub table_rows: Option<i64>,
        pub avg_row_length: Option<i64>,
        pub data_length: Option<i64>,
        pub max_data_length: Option<i64>,
        pub index_length: Option<i64>,
        pub data_free: Option<i64>,
        pub auto_increment: Option<i64>,
        pub create_time: Option<chrono::DateTime<chrono::Utc>>,
        pub update_time: Option<chrono::DateTime<chrono::Utc>>,
        pub check_time: Option<chrono::DateTime<chrono::Utc>>,
        pub table_collation: Option<String>,
        pub checksum: Option<i64>,
        pub create_options: Option<String>,
        pub table_comment: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
    pub enum Relation {}

    impl ActiveModelBehavior for ActiveModel {}

    pub use Entity as Tables;
}

/// Entity for information_schema.columns
pub mod columns {
    use super::*;
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "columns", schema_name = "information_schema")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_name: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub column_name: String,
        pub ordinal_position: Option<i32>,
        pub column_default: Option<String>,
        pub is_nullable: Option<String>,
        pub data_type: Option<String>,
        pub character_maximum_length: Option<i64>,
        pub character_octet_length: Option<i64>,
        pub numeric_precision: Option<i32>,
        pub numeric_scale: Option<i32>,
        pub datetime_precision: Option<i32>,
        pub character_set_name: Option<String>,
        pub collation_name: Option<String>,
        pub column_type: Option<String>,
        pub column_key: Option<String>,
        pub extra: Option<String>,
        pub privileges: Option<String>,
        pub column_comment: Option<String>,
        pub generation_expression: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
    pub enum Relation {}

    impl ActiveModelBehavior for ActiveModel {}

    pub use Entity as Columns;
}

/// Entity for information_schema.key_column_usage (foreign keys)
pub mod key_column_usage {
   use super::*;
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "key_column_usage", schema_name = "information_schema")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_name: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub table_name: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub column_name: String,
        pub ordinal_position: Option<i32>,
        pub position_in_unique_constraint: Option<i32>,
        pub referenced_table_schema: Option<String>,
        pub referenced_table_name: Option<String>,
        pub referenced_column_name: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
    pub enum Relation {}

    impl ActiveModelBehavior for ActiveModel {}

    pub use Entity as KeyColumnUsage;
}

/// Entity for information_schema.referential_constraints
pub mod referential_constraints {
    use super::*;
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "referential_constraints", schema_name = "information_schema")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_name: String,
        pub unique_constraint_catalog: Option<String>,
        pub unique_constraint_schema: Option<String>,
        pub unique_constraint_name: Option<String>,
        pub match_option: Option<String>,
        pub update_rule: Option<String>,
        pub delete_rule: Option<String>,
        pub table_name: Option<String>,
        pub referenced_table_name: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
    pub enum Relation {}

    impl ActiveModelBehavior for ActiveModel {}

    pub use Entity as ReferentialConstraints;
}

/// Entity for information_schema.table_constraints
pub mod table_constraints {
    use super::*;
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "table_constraints", schema_name = "information_schema")]
    pub struct Model {
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_catalog: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_schema: String,
        #[sea_orm(primary_key, auto_increment = false)]
        pub constraint_name: String,
        pub table_schema: Option<String>,
        pub table_name: Option<String>,
        pub constraint_type: Option<String>,
    }

    #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
    pub enum Relation {}

    impl ActiveModelBehavior for ActiveModel {}

    pub use Entity as TableConstraints;
}

// Re-export all entities for easier access
pub use columns::Columns;
pub use key_column_usage::KeyColumnUsage;
pub use referential_constraints::ReferentialConstraints;
pub use table_constraints::TableConstraints;
pub use tables::Tables;

/// Helper struct for database metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableInfo {
    pub name: String,
    pub schema: String,
    pub table_type: String,
    pub comment: Option<String>,
}

/// Helper struct for column metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnInfo {
    pub name: String,
    pub data_type: String,
    pub is_nullable: bool,
    pub default_value: Option<String>,
    pub is_primary_key: bool,
    pub is_foreign_key: bool,
    pub character_maximum_length: Option<i64>,
    pub numeric_precision: Option<i32>,
    pub numeric_scale: Option<i32>,
    pub comment: Option<String>,
}

impl From<columns::Model> for ColumnInfo {
    fn from(column: columns::Model) -> Self {
        Self {
            name: column.column_name,
            data_type: column.data_type.unwrap_or_default(),
            is_nullable: column.is_nullable.as_deref() == Some("YES"),
            default_value: column.column_default,
            is_primary_key: column.column_key.as_deref() == Some("PRI"),
            is_foreign_key: column.column_key.as_deref() == Some("MUL"),
            character_maximum_length: column.character_maximum_length,
            numeric_precision: column.numeric_precision,
            numeric_scale: column.numeric_scale,
            comment: column.column_comment,
        }
    }
}

impl From<tables::Model> for TableInfo {
    fn from(table: tables::Model) -> Self {
        Self {
            name: table.table_name,
            schema: table.table_schema,
            table_type: table.table_type.unwrap_or_default(),
            comment: table.table_comment,
        }
    }
}